/*
 * Copyright 2009 Gal Dolber
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.dragdrop.client.impl;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.dragdrop.client.DragController;
import com.google.gwt.user.dragdrop.client.DropController;
import com.google.gwt.user.dragdrop.client.util.DragHandler;

/**
 * Standard drag implementation
 */
public class DragImpl extends DragHandler {

	Boolean fixed = true;
	Boolean limit = false;
	int offsetx;
	int offsety;
	int relativex;
	int relativey;

	/**
	 * Get the parent
	 * 
	 * @param controller
	 *            MouseController
	 * @return Parent
	 */
	public AbsolutePanel getContainer(DragController controller) {
		return (AbsolutePanel) controller.getWidget().getParent();
	}

	/**
	 * Offset mouse x from the widget
	 */
	public int getOffsetX() {
		return offsetx;
	}

	/**
	 * Offset mouse y from the widget
	 */
	public int getOffsetY() {
		return offsety;
	}

	/**
	 * Relative mouse x from the parent
	 */
	public int getRelativeX() {
		return relativex;
	}

	/**
	 * Relative mouse y from the parent
	 */
	public int getRelativeY() {
		return relativey;
	}

	@Override
	public void onDragEnd(DragController controller) {
		super.onDragEnd(controller);
		DropController.onDragDrop(controller);
	}

	@Override
	public void onDragMove(DragController controller) {
		super.onDragMove(controller);
		if (controller.getButton() != NativeEvent.BUTTON_LEFT) {
			return;
		}

		DropController.onDragMove(controller);

		Widget widget = controller.getWidget();
		AbsolutePanel parent = getContainer(controller);

		MouseEvent<?> event = controller.getCurrentEvent();

		// Save relative position to the parent
		relativex = event.getRelativeX(parent.getElement())
				- parent.getElement().getScrollLeft();
		relativey = event.getRelativeY(parent.getElement())
				- parent.getElement().getScrollTop();

		// Fixed dragging
		if (fixed) {
			relativex -= offsetx;
			relativey -= offsety;
		}

		// Limited to the container sides
		if (limit) {
			int maxx = parent.getOffsetWidth() - widget.getOffsetWidth();
			relativex = (relativex < 0) ? 0 : (relativex > maxx ? maxx
					: relativex);

			int maxy = parent.getOffsetHeight() - widget.getOffsetHeight();
			relativey = (relativey < 0) ? 0 : (relativey > maxy ? maxy
					: relativey);
		}

		// Move the widget the the new position
		parent.setWidgetPosition(widget, getRelativeX(), getRelativeY());
	}

	@Override
	public void onDragStart(DragController controller) {
		super.onDragStart(controller);
		MouseEvent<?> event = controller.getCurrentEvent();
		Widget widget = controller.getWidget();

		// Save relative position to the parent
		relativex = event.getRelativeX(getContainer(controller).getElement());
		relativey = event.getRelativeY(getContainer(controller).getElement());

		// Save widget initial offset position
		offsetx = event.getRelativeX(widget.getElement());
		offsety = event.getRelativeY(widget.getElement());
	}

	/**
	 * Sets if the dragging its fixed with the mouse initial offset
	 * 
	 * @param value
	 */
	public void setFixed(boolean value) {
		fixed = value;
	}

	/**
	 * Sets if the dragging its limit to the container sides
	 * 
	 * @param value
	 */
	public void setLimit(boolean value) {
		limit = value;
	}

	@Override
	public String toString() {
		return "Drag";
	}
}
